/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.lpcluster;

import android.app.IntentService;
import android.app.Notification;
import android.content.Intent;
import android.content.res.AssetManager;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Service class to carry out loop-perforated K-Means
 * @author edward
 */
public class LPCluster extends IntentService {
	
	static StringBuilder sOutput = new StringBuilder();
	
	private AssetManager manager = MainActivity.singleton.getAssets();
	private boolean interrupted = false;
	private BufferedWriter logOut = null;
	
	public LPCluster() {
		super("LPCluster");		
	}
	
	/**
	 * Output results in console and store in sOutput
	 * @param sPost Results to print
	 */
	static void post(final String sPost) {
		if (sOutput.length() > 500) sOutput.delete(0, sOutput.length());
		sOutput.append(sPost).append('\n');
		MainActivity.singleton.updateText();
	}
	
	/**
	 * Close output file when app is closed
	 */
	@Override
	public void onDestroy() {
		interrupted = true;
		try {
			logOut.close();
		} catch (IOException ex) {}
		super.onDestroy();
	}
	
	/**
	 * Experiment starts upon receiving Intent
	 * @param intent Intent to start experiment with start time (nCreateTime)
	 */
	@Override
	protected void onHandleIntent(Intent intent) {
		startForeground(0, new Notification());  // Enforce high run priority
		sOutput.delete(0, sOutput.length());
		
		// Prepare output file
		try {
			logOut = new BufferedWriter(new FileWriter(
				new File(Environment.getExternalStorageDirectory(), 
						 intent.getLongExtra("nCreateTime", -1)+"_LPCluster.log")));
		} catch (IOException ex) {
			Log.e("LPCluster", ex.toString());
		}

		kMeansAction();  // Execute experiment
		stopSelf();  // Experiment finished -> Stop service
		MainActivity.singleton.stop(null);  // Stop PowerTutor without starting again
	}
	
	/**
	 * Centroid selection schemes
	 */
	static enum CentroidType {
		Group, Super, Virtual
	}
	
	static long nSeed;  // Seed for random number generator
	static long getSeed() {
		return nSeed;
	}

	/**
	 * Load input documents and keywords for processing
	 * @return KMeans object containing the data files
	 * @throws IOException if data files are not found
	 */
	KMeans retrieveData() throws IOException {
		List<WebPage> webPages = new ArrayList<WebPage>();

		// Detect if data file path exists
		String sFilePath = "0.txt";
		boolean exists = true;
		try {
			manager.open(sFilePath).close();
		} catch (IOException ex) {
			exists = false;
		}

		// ***** LP-LOC # 1a *****
		// Read 1.txt, 2.txt, ... from predefined path as data points (web pages)
		for (int i = 0; exists; i++) {
			webPages.add(WebPage.webPageWithFilePath(sFilePath));
			sFilePath = (i + 1) + ".txt";			
			try {
				manager.open(sFilePath).close();
			} catch (IOException ex) {
				exists = false;
			}
		}

		return KMeans.kMeansWithData(webPages);
	}
		
	/**
	 * Main method for executing the K-Means experiments
	 */
	void kMeansAction() {
		nSeed = 1;
		
		try {
			post("Retrieving data...");
			KMeans kMeans = retrieveData();
			post("PowerTutor starts...");
			MainActivity.singleton.start();

			// ***** NO PERF (proper setup of experiments) *****
			for (CentroidType centroidType : CentroidType.values()) {
				for (int nNumClusters=2; nNumClusters<=50; nNumClusters+=(nNumClusters==2?3:5)) {
					for (Cluster.nCentroidPerf=0; Cluster.nCentroidPerf<=90; Cluster.nCentroidPerf+=30)
					{
						// Statistics counters for each experiment
						post("Running "+nNumClusters+" clusters with "+Cluster.nCentroidPerf+"% perf...");
						int i = 1;
						double nSSESum = 0;
						long nTime = 0;
						
						// ***** NO PERF (proper setup of experiments) *****
						for (; i<=50; i++) {
							nSeed = i;
							
							// Manual cancellation of experiment
							if (interrupted) {
								logOut.close();
								return;
							}
							
							// Time experiment
							long nStart = System.currentTimeMillis();
							double nExpSum = kMeans.cluster(nNumClusters, centroidType);						
							long nStop = System.currentTimeMillis();
							
							// Accumulate statistics
							nTime += nStop-nStart;					
							nSSESum += nExpSum;
							logOut.write(nExpSum+" ");
						}
						
						// Output results
						String sLog = String.format("%s %d %d %.2f %d",centroidType,nNumClusters,
							Cluster.nCentroidPerf,nSSESum/i,nTime);
						post(sLog);
						logOut.write("\r\n"+sLog+"\r\n");
						
						// Sleep default worker thread to clear statistics
						try {
							Thread.sleep(3000);
						} catch (InterruptedException ex) {
						}
						MainActivity.singleton.stop(centroidType+"_"+nNumClusters+"_"+Cluster.nCentroidPerf);
					}
				}
			}
		} catch (Exception ex) {
			// Error in execution
			System.out.println(ex);
			System.err.println(ex);
			post(ex+"\n"+Arrays.deepToString(ex.getStackTrace()));
		}
	}
}
